package org.xhy.sniffer.plugin;

import net.bytebuddy.description.NamedElement;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.xhy.sniffer.match.ClassMatch;

import java.util.*;

import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.not;

/**
 * @description: 存储所有插件
 * @gitee: https://gitee.com/XhyQAQ
 * @copyright: B站: https://space.bilibili.com/152686439
 * @Author: Xhy
 * @CreateTime: 2024-07-11 20:30
 */
public class PluginFinder {


    /**
     * 用于存储ClassMatch类型为IndirectMatch的插件
     */
    private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new ArrayList<>();
    /**
     * 对插件进行分类
     * @param plugins 加载到的所有的插件
     */
    public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
        for (AbstractClassEnhancePluginDefine plugin : plugins) {
            ClassMatch classMatch = plugin.enhanceClass();
            if (classMatch == null) {
                continue;
            }
            signatureMatchDefine.add(plugin);
        }
    }

    /**
     * - 通过加载器获取插件，每个插件都会实现类匹配器
     * - 通过遍历将插件的匹配器拼接（build） 例如：named().or(named()) 并返回
     * - 将插件传入转换器，在转换器中遍历插件找到对应的匹配的类，如果匹配到，则由插件的拦截器进行插桩并返回
     * - 如何找到对应匹配的类：在此之前就已经存放了拦截的类名
     */

    /**
     * 返回已加载的所有插件最终拼接后的条件
     * @return  plugin1_junction.or(plugin2_junction).or(plugin3_junction)
     */
    public ElementMatcher<? super TypeDescription> buildMatch() {
        ElementMatcher.Junction<? super TypeDescription> junction = new ElementMatcher.Junction.AbstractBase<NamedElement>() {

            @Override
            public boolean matches(NamedElement target) {
                // 当某个类第一次被加载时都会回调至此 a.b.C
                return false;
            }
        };
        // 只增强类
        junction = junction.and(not(isInterface()));
        for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
            ClassMatch classMatch = pluginDefine.enhanceClass();
            junction = junction.or(classMatch.buildJunction());
        }
        return junction;
    }

    /**
     * 找到对应的插件集合
     * @param typeDescription 当前匹配到的类
     * @return typeDescription 对应的插件集合
     */
    public List<AbstractClassEnhancePluginDefine> find(TypeDescription typeDescription) {
        List<AbstractClassEnhancePluginDefine> matchedPlugins = new LinkedList<>();
        // 处理signatureMatchDefine
        for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
            final ClassMatch classMatch = pluginDefine.enhanceClass();
            if (classMatch.isMatch(typeDescription)) {
                matchedPlugins.add(pluginDefine);
            }
        }
        return matchedPlugins;
    }
}
